package com.powernode.ssm.springAnalysis.a04;

import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.InjectionMetadata;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.StandardEnvironment;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// AutowiredAnnotationBeanPostProcessor 运行分析
public class DigInAutowired {
    public static void main(String[] args) throws Throwable {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        beanFactory.registerSingleton("bean8", new Bean8()); // 创建过程,依赖注入,初始化
        beanFactory.registerSingleton("bean7", new Bean7());
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver()); // @Value
        beanFactory.addEmbeddedValueResolver(new StandardEnvironment()::resolvePlaceholders); // ${} 的解析器

        // 1. 查找哪些属性、方法加了 @Autowired, 这称之为 InjectionMetadata
        AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
        processor.setBeanFactory(beanFactory);
        Bean9 bean9 = new Bean9();
        System.out.println("解析注解之前："+bean9);
        processor.postProcessProperties(null, bean9, "bean9"); // 执行依赖注入 @Autowired @Value
        System.out.println("解析注解之后："+bean9);

        /* postProcessProperties方法流程解析 */
        /**
         * 找到Bean9中哪些成员变量和方法加了@Autowire注解
         * 封装到InjectionMetadata对象中，其中他的成员变量injectedElements储存了这些
         * 加了@Autowire注解的成员变量和方法
         */
        Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
        findAutowiringMetadata.setAccessible(true);
        InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean9", Bean9.class, null);// 获取 Bean9 上加了 @Value @Autowired 的成员变量，方法参数信息
        System.out.println(metadata);

         //2. 调用 InjectionMetadata 来进行依赖注入, 注入时按类型查找值
        metadata.inject(bean9, "bean9", null);
        System.out.println(bean9);

        /* postProcessProperties方法流程解析 */

        /* metadata.inject方法流程解析 */

        // 3. 如何按类型查找值
        //根据成员变量去找bean
        Field bean8 = Bean9.class.getDeclaredField("bean8");
        DependencyDescriptor dd1 = new DependencyDescriptor(bean8, false);
        Object o = beanFactory.doResolveDependency(dd1, null, null, null);
        System.out.println("根据成员变量去找bean8："+o);

        //根据setBean7方法去找bean
        Method setBean7 = Bean9.class.getDeclaredMethod("setBean7", Bean7.class);
        DependencyDescriptor dd2 =
                new DependencyDescriptor(new MethodParameter(setBean7, 0), false);
        Object o1 = beanFactory.doResolveDependency(dd2, null, null, null);
        System.out.println("根据setBean7方法去找bean7："+o1);

        //根据setHome方法去找bean
        Method setHome = Bean9.class.getDeclaredMethod("setHome", String.class);
        DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
        Object o2 = beanFactory.doResolveDependency(dd3, null, null, null);
        System.out.println("根据setHome方法去找home字符串："+o2);

        /* metadata.inject方法流程解析 */

    }
}
